package com.health.annotation;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.health.entity.pojo.vo.AdminVO;
import com.health.mapper.AdminLogMapper;
import com.health.service.IAdminService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;

/**
 * @Description
 * @Author konglz
 * @Data 2023/4/21 9:26
 */
@Aspect
@Component
@Slf4j
public class AdminLogAop {

    @Autowired
    private AdminLogMapper adminLogMapper;

    Date startTime;

    @Autowired
    IAdminService adminService;

    /***
     * @Description: 切点，用于拦截添加@AdminLog注解的方法
     * @return: void
     * @Author: konglz
     * @Date: 2023/4/21
     */

    @Pointcut(value = "@annotation(adminLog)")
    public void pointcut(AdminLog adminLog) {

    }

    /**
     * @Description: 环绕通知，在被拦截的方法之前和之后可以做增强逻辑, 连接点：一般指拦截到的方法，我们需要从连接点进行切面编程，也就是通知
     * @return: java.lang.Object
     * @Author: konglz
     * @Date: 2023/4/21
     */
    @Around(value = "pointcut(adminLog)")
    public Object around(ProceedingJoinPoint joinPoint, AdminLog adminLog) throws Throwable {
        //设置一个时间，用于统计开始增强逻辑的执行时间
        startTime = new Date();
        Signature sig = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) sig;
        if (methodSignature.getName().equals("logout")) {
            try {
                handle(joinPoint, null);
            } catch (Exception e) {
                e.printStackTrace();
                throw new Exception();
            }
            Object result = joinPoint.proceed();
            return result;
        } else {
            //先执行业务逻辑
            Object result = joinPoint.proceed();
            try {
                handle(joinPoint, result);
            } catch (Exception e) {
                e.printStackTrace();
                throw new Exception();
            }
            return result;
        }

    }

    private void handle(ProceedingJoinPoint joinPoint, Object result) throws NoSuchMethodException {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();


        Signature sig = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) sig;
        Object target = joinPoint.getTarget();
        Method currentMethod = target.getClass().getMethod(methodSignature.getName(), methodSignature.getParameterTypes());

        //获取操作名称
        AdminLog annotation = currentMethod.getAnnotation(AdminLog.class);
        String operationName = annotation.value();

        String type = request.getMethod();
        String ip = request.getRemoteHost();
        String url = request.getRequestURI();
        Date endTime = new Date();
        String[] parameterNames = methodSignature.getParameterNames();
        String paramsJson = JSONObject.toJSONString(parameterNames);

        com.health.entity.AdminLog adminLog1 = new com.health.entity.AdminLog();
        adminLog1.setIp(ip);
        adminLog1.setType(type);
        adminLog1.setRequestUrl(url);
        adminLog1.setParams(paramsJson);
        adminLog1.setResult(JSONObject.toJSONString(result));
        adminLog1.setOperationName(operationName);
        adminLog1.setMethodName(methodSignature.getName());
        adminLog1.setClassPath(target.getClass().getName());
        adminLog1.setUsername(SecurityUtils.getSubject().getPrincipal().toString());
        adminLog1.setSpendTime(endTime.getTime() - startTime.getTime());

        AdminVO userInfo = adminService.findUserInfo(SecurityUtils.getSubject().getPrincipal().toString());
        adminLog1.setRoles(userInfo.getRoles());

        adminLogMapper.insert(adminLog1);
    }

}

